﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Krs.Ats.IBNet;
using Krs.Ats.IBNet.Contracts;
using Systemathics.FrameWork;
using Systemathics.FrameWork.Interfaces;

namespace Systemathics.Providers
{
    public partial class IB : IDataProvider
    {
        #region IConnection Members
        
        string IConnection.Name
        {
            get { return PROVIDER_NAME; }
        }
        bool IConnection.isConnected
        {
            get
            {
                if (client != null)
                {
                    isConnected = client.Connected;
                    return isConnected;
                }
                return false;
            }
        }
        void IConnection.Connect()
        {
            try
            {
                if (!isConnected)
                {
                    client = new IBClient { ThrowExceptions = true };
                    client.SetServerLogLevel(LogLevel.Detail);
                    client.Connect(HOST, PORT, CLIENT_ID);
                    client.RequestAutoOpenOrders(true); // if true, TWS Order will be associated to ap iin OrderStatus CallBack

                    if (client.ServerVersion > 0)
                    {
                        client.TickPrice += TickPrice;
                        client.TickSize += TickSize;
                        client.Error += Error;
                        client.NextValidId += NextValidId;
                        client.UpdateMarketDepth += UpdateMarketDepth;
                        client.HistoricalData += HistoricalData;

                        //client.OpenOrder += OpenOrder;
                        client.OrderStatus += OrderStatus;
                        client.ExecDetails += ExecutionDetails;

                        client.UpdateAccountValue += UpdateAccountValue;
                        client.UpdatePortfolio += UpdatePortfolio;

                        client.ContractDetails += ContractDetails;
                        client.ConnectionClosed += ConnectionClosed;
                    }

                    isConnected = client.Connected;
                    if (isConnected)
                    {
                        client.RequestIds(1);
                        _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Connected, Time.Now.TimeOfDay));
                        _EmitError(this, new FireMessageEventArgs("IB Logon Succeed", Time.Now.TimeOfDay));
                        //client.RequestAllOpenOrders(); // Call Back in OpenOrder(object sender, OpenOrderEventArgs e)
                        // client.RequestOpenOrders();    // Call Back in OrderStatus(object sender, Krs.Ats.IBNet.OrderStatusEventArgs e)
                        client.RequestAccountUpdates(true, ACCOUNT_CODE); //UpdateAccountValue(object sender, UpdateAccountValueEventArgs e) && UpdatePortfolio(object sender, UpdatePortfolioEventArgs e)
                    }
                }
            }
            catch (Exception ex)
            {
                _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
                _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
            }
        }
        void IConnection.Disconnect()
        {
            if (isConnected)
            {
                try
                {
                    client.Disconnect();

                    client.TickPrice -= TickPrice;
                    client.TickSize -= TickSize;
                    client.Error -= Error;
                    client.NextValidId -= NextValidId;
                    client.UpdateMarketDepth -= UpdateMarketDepth;
                    client.HistoricalData -= HistoricalData;

                    client.OpenOrder -= OpenOrder;
                    client.OrderStatus -= OrderStatus;
                    client.ExecDetails -= ExecutionDetails;

                    client.UpdateAccountValue -= UpdateAccountValue;
                    client.ConnectionClosed -= ConnectionClosed;

                    isConnected = client.Connected;
                    if (!isConnected)
                        _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
                }
                catch (Exception ex)
                {
                    _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
                }
            }
        }
        void IConnection.Suscribe(Instrument instrument)
        {
            if (isConnected)
            {
                if (!LastFeeds.Where(u => u.Value.Trade.Id == instrument.Id).Any())
                {
                    Contracts[instrument.Id] = BuildContract(instrument);
                    if (Contracts[instrument.Id] != null)
                    {
                        var depth = 0;
                        switch (instrument.StaticData.Type)
                        {
                            case InstrumentType.Bond:
                                depth = BOND_DEPTH;
                                break;
                            case InstrumentType.ETF:
                                depth = ETF_DEPTH;
                                break;
                            case InstrumentType.Future:
                                depth = FUTURE_DEPTH;
                                break;
                            case InstrumentType.Option:
                                depth = OPTION_DEPTH;
                                break;
                            case InstrumentType.Index:
                                depth = INDEX_DEPTH;
                                break;
                            case InstrumentType.Cash:
                                depth = CASH_DEPTH;
                                break;
                            case InstrumentType.Unknown:
                                depth = 0;
                                break;
                        }
                       client.RequestMarketData(FeedSuscriptionNumber, Contracts[instrument.Id], null, false, false);
                       client.RequestMarketDepth(FeedSuscriptionNumber, Contracts[instrument.Id], depth);
                       _EmitError(this, new FireMessageEventArgs("Suscribing ..." + instrument.StaticData.Name, Time.Now.TimeOfDay));
                    }
                    else
                        _EmitError(this, new FireMessageEventArgs("Contract == null : Cannot Suscribe " + instrument.StaticData.Name, Time.Now.TimeOfDay));
                }
            }
        }
        void IConnection.Unsubscribe(Instrument instrument)
        {
            if (LastFeeds.Where(u => u.Value.Trade.Id == instrument.Id).Any())
            {
                var id = LastFeeds.Where(u => u.Value.Trade.Id == instrument.Id).FirstOrDefault().Key;
                client.CancelMarketData(id);
                client.CancelMarketDepth(id);
                LastFeeds.Remove(id);
            }
        }

        event EventHandler<FireMessageEventArgs> IConnection.EmitError
        {
            add { _EmitError += value; }
            remove { _EmitError -= value; }
        }
        event EventHandler<FireMessageEventArgs> IConnection.EmitConnectionStatus
        {
            add { _EmitConnectionStatus += value; }
            remove { _EmitConnectionStatus -= value; }
        }

        #endregion

        #region IDataProvider Members

        void IDataProvider.GetHistoricalData(DateTime begin, DateTime end, Data dt, Guid id, int? barSize)
        {
            try
            {
                switch (dt)
                {
                    case Data.Bar:
                        var requestId = FeedSuscriptionNumber++;
                        client.RequestHistoricalData(requestId, Contracts[id], DateTime.Today, end - begin, SecondsToBarSize((int)barSize), HistoricalDataType.Trades, 0);
                        HistoricalRequests[requestId] = new BarSeries(id.ToString()) { Id = id, BarSize = barSize, BarType = BarType.Seconds };
                        break;
                    case Data.Quote:
                        _EmitError(this, new FireMessageEventArgs("No Historical Quotes Support for IB", Time.Now.TimeOfDay));
                        break;
                    case Data.Trade:
                        _EmitError(this, new FireMessageEventArgs("No Historical Trades Support for IB", Time.Now.TimeOfDay));
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
            }
        }
        void IDataProvider.UpdateInstruments()
        {
            using (var db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString()))
            {
                var startRequestId = 100000;
                var query = db.DBTickers.Where(u => u.Provider == PROVIDER_NAME);
                if (query.Any())
                {
                    foreach (DBTickers ticker in query)
                    {
                        ticker.DBInstrumentsReference.Load();
                        var contract = BuildContract(new Instrument(ticker.DBInstruments.ID ,null ,null));
                        if(contract != null)
                        {
                            client.RequestContractDetails(startRequestId, contract);
                            startRequestId++;
                        }
                    }
                }
            }
        }
        void IDataProvider.UpdateCurrencies()
        {
            client.TickPrice += UpdateCurrenciesTickPrice;
            foreach (KeyValuePair<int, String> kvp in CurrenciesToUpdate)
            {
                if (!LastFeeds.ContainsKey(kvp.Key))
                {
                    LastFeeds.Add(kvp.Key, new LastFeed(Guid.NewGuid()));
                    client.RequestMarketData(kvp.Key, new Forex("EUR", kvp.Value), null, false, false);
                }
            }
            db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString());
            db.AcceptAllChanges();
        }

        event EventHandler<MarketData> IDataProvider.EmitNewMarketData
        {
            add { _EmitNewMarketData += value; }
            remove { _EmitNewMarketData -= value; }
        }
        event EventHandler<Trade> IDataProvider.EmitNewTrade
        {
            add { _EmitNewTrade += value; }
            remove { _EmitNewTrade -= value; }
        }
        event EventHandler<Blotter> IDataProvider.EmitNewBlotter
        {
            add { _EmitNewBlotter += value; }
            remove { _EmitNewBlotter -= value; }
        }
        event EventHandler<BarSeries> IDataProvider.EmitBarSeries
        {
            add { _EmitBarSeries += value; }
            remove { _EmitBarSeries -= value; }
        }
        event EventHandler<TradeSeries> IDataProvider.EmitTradeSeries
        {
            add { _EmitTradeSeries += value; }
            remove { _EmitTradeSeries -= value; }
        }
        event EventHandler<QuoteSeries> IDataProvider.EmitQuoteSeries
        {
            add { _EmitQuoteSeries += value; }
            remove { _EmitQuoteSeries -= value; }
        }

        #endregion

        #region IB's Feed CallBacks

        private static int BarSizeToSeconds(BarSize bs)
        {
            switch (bs)
            {
                case BarSize.OneSecond:

                case BarSize.FiveSeconds:
                    return 5;
                case BarSize.FifteenSeconds:
                    return 15;
                case BarSize.ThirtySeconds:
                    return 30;
                case BarSize.OneMinute:
                    return 60;
                case BarSize.TwoMinutes:
                    return 120;
                case BarSize.FiveMinutes:
                    return 300;
                case BarSize.FifteenMinutes:
                    return 900;
                case BarSize.ThirtyMinutes:
                    return 1800;
                case BarSize.OneHour:
                    return 3600;
                case BarSize.OneDay:
                    return 86400;
                case BarSize.OneWeek:
                    return 604800;
                case BarSize.OneMonth:
                    return 2592000;
                case BarSize.OneYear:
                    return 31104000;
            }
            return 0;
        }
        private static BarSize SecondsToBarSize(int bs)
        {
            if (bs == 1)
                return BarSize.OneSecond;
            if (bs > 1 && bs <= 5)
                return BarSize.FiveSeconds;
            if (bs > 5 && bs <= 15)
                return BarSize.FifteenSeconds;
            if (bs > 15 && bs <= 30)
                return BarSize.ThirtySeconds;
            if (bs > 30 && bs <= 60)
                return BarSize.OneMinute;
            if (bs > 60 && bs <= 120)
                return BarSize.TwoMinutes;
            if (bs > 120 && bs <= 300)
                return BarSize.FiveMinutes;
            if (bs > 300 && bs <= 900)
                return BarSize.FifteenMinutes;
            if (bs > 900 && bs <= 1800)
                return BarSize.ThirtyMinutes;
            if (bs > 1800 && bs <= 3600)
                return BarSize.OneHour;
            if (bs > 3600 && bs <= 86400)
                return BarSize.OneDay;
            if (bs > 86400 && bs <= 604800)
                return BarSize.OneWeek;
            if (bs > 604800 && bs <= 2592000)
                return BarSize.OneMonth;
            if (bs > 2592000 && bs <= 31104000)
                return BarSize.OneMonth;
            return (BarSize)0;
        }
        private Contract BuildContract(Instrument instr)
        {
            var symbol = instr.Ticker;
            if (symbol != String.Empty)
            {
                if (instr.StaticData.Type == InstrumentType.Cash && instr.StaticData.Classe == AssetClass.Equity)
                {
                    FeedSuscriptionNumber++;
                    LastFeeds.Add(FeedSuscriptionNumber, new LastFeed(instr.Id));
                    return new Equity(symbol, instr.StaticData.Exchange.Place) { Currency = instr.StaticData.Currency.Ticker }; //,PrimaryExchange = "SMART"
                }
                if (instr.StaticData.Type == InstrumentType.Index)
                {
                    FeedSuscriptionNumber++;
                    LastFeeds.Add(FeedSuscriptionNumber, new LastFeed(instr.Id));
                    return new Index(symbol, instr.StaticData.Exchange.Place) { Currency = instr.StaticData.Currency.Ticker };
                }
                if (instr.StaticData.Type == InstrumentType.Future)
                {
                    var expiry = String.Empty;
                    if (instr.StaticData.Maturity != null)
                        expiry = String.Format("{0:yyyyMMdd}", (DateTime)instr.StaticData.Maturity);
                    FeedSuscriptionNumber++;
                    LastFeeds.Add(FeedSuscriptionNumber, new LastFeed(instr.Id));
                    return new Future(symbol, instr.StaticData.Exchange.Place, expiry, instr.StaticData.Currency.Ticker,new decimal(instr.StaticData.Rules.TickValue));
                }
                if (instr.StaticData.Classe == AssetClass.Forex && instr.StaticData.Type == InstrumentType.Cash)
                {
                    FeedSuscriptionNumber++;
                    LastFeeds.Add(FeedSuscriptionNumber, new LastFeed(instr.Id));
                    var s = symbol.Split(new[] { '.' }, 2);
                    return new Forex(s[0], s[1]);
                }
            }
            else
                _EmitError(this, new FireMessageEventArgs(instr.StaticData.Name + " Not present in " + PROVIDER_NAME + ": No suscription", Time.Now.TimeOfDay));
            return null;
        }
        private void UpdateCurrenciesTickPrice(object sender, TickPriceEventArgs e)
        {
            var currency = CurrenciesToUpdate[e.TickerId];
            CurrenciesCounter[currency] = true;
            db.DBCurrency.Where(y => y.Ticker == currency).FirstOrDefault().ReferencePrice = Math.Round(1 / (double)e.Price, 6);

            if (CurrenciesCounter.Values.Where(u => u == false).Count() == 0)
            {
                foreach (var tickerId in CurrenciesToUpdate.Keys)
                {
                    client.CancelMarketData(tickerId);
                    LastFeeds.Remove(tickerId);
                }
                _EmitError(this, new FireMessageEventArgs("Currencies Update Finnished", Time.Now.TimeOfDay));
                client.TickPrice -= UpdateCurrenciesTickPrice;
                db.SaveChanges(true);
                db.Dispose();
            }
        }
        private void UpdateMarketDepth(object sender, UpdateMarketDepthEventArgs e)
        {
            if (LastFeeds.ContainsKey(e.TickerId))
            {
                var processIt = false;
                var deleteIt = false;
                var ql = (QuoteLevel)(e.Position);

                switch (e.Operation)
                {
                    case MarketDepthOperation.Insert:
                        processIt = true;
                        break;
                    case MarketDepthOperation.Update:
                        processIt = true;
                        break;
                    case MarketDepthOperation.Delete:
                        deleteIt = true;
                        break;
                }

                if (processIt)
                {
                    switch (e.Side)
                    {
                        case MarketDepthSide.Ask:
                            LastFeeds[e.TickerId].Blotter[ql].Ask = e.Price;
                            LastFeeds[e.TickerId].Blotter[ql].AskSize = e.Size;
                            break;
                        case MarketDepthSide.Bid:
                            LastFeeds[e.TickerId].Blotter[ql].Bid = e.Price;
                            LastFeeds[e.TickerId].Blotter[ql].BidSize = e.Size;
                            break;
                    }
                    switch (e.Side)
                    {
                        case MarketDepthSide.Ask:
                            if (ql == QuoteLevel.One)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_1 | TickInfo.AskSize_1;
                            if (ql == QuoteLevel.Two)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_2 | TickInfo.AskSize_2;
                            if (ql == QuoteLevel.Three)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_3 | TickInfo.AskSize_3;
                            if (ql == QuoteLevel.Four)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_4 | TickInfo.AskSize_4;
                            if (ql == QuoteLevel.Five)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_5 | TickInfo.AskSize_5;
                            break;
                        case MarketDepthSide.Bid:
                            if (ql == QuoteLevel.One)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_1 | TickInfo.BidSize_1;
                            if (ql == QuoteLevel.Two)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_2 | TickInfo.BidSize_2;
                            if (ql == QuoteLevel.Three)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_3 | TickInfo.BidSize_3;
                            if (ql == QuoteLevel.Four)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_4 | TickInfo.BidSize_4;
                            if (ql == QuoteLevel.Five)
                                LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_5 | TickInfo.BidSize_5;
                            break;
                    }
                }
                else if (deleteIt)
                {
                    switch (e.Side)
                    {
                        case MarketDepthSide.Ask:
                            LastFeeds[e.TickerId].Blotter[ql].Ask = 0;
                            LastFeeds[e.TickerId].Blotter[ql].AskSize = 0;
                            break;
                        case MarketDepthSide.Bid:
                            LastFeeds[e.TickerId].Blotter[ql].Bid = 0;
                            LastFeeds[e.TickerId].Blotter[ql].BidSize = 0;
                            break;
                    }

                }
                _EmitNewBlotter(this, LastFeeds[e.TickerId].Blotter);
            }
        }
        private void TickSize(object sender, TickSizeEventArgs e)
        {
            if (LastFeeds.ContainsKey(e.TickerId))
            {
                var emitTrade = false;
                var emitlevelOne = false;

                switch (e.TickType)
                {
                    case TickType.BidSize:
                        emitlevelOne = true;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].BidSize = e.Size;
                        LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.BidSize_1;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Time = Time.Now;
                        break;
                    case TickType.AskSize:
                        emitlevelOne = true;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].AskSize = e.Size;
                        LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.AskSize_1;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Time = Time.Now;
                        break;
                    case TickType.LastSize:
                        emitTrade = true;
                        LastFeeds[e.TickerId].Trade.Size = e.Size;
                        LastFeeds[e.TickerId].Trade.Time = Time.Now;
                        break;
                }
                if (emitTrade && LastFeeds[e.TickerId].TradeCheck)
                {
                    LastFeeds[e.TickerId].Trade.TickInfo = TickInfo.LastSize;
                    _EmitNewTrade(this, LastFeeds[e.TickerId].Trade);
                }
                else
                    LastFeeds[e.TickerId].CheckTrade();

                if (emitlevelOne && LastFeeds[e.TickerId].BlotterCheck)
                    _EmitNewBlotter(this, LastFeeds[e.TickerId].Blotter);
                else
                    LastFeeds[e.TickerId].CheckBlotter(QuoteLevel.One);
            }
        }
        private void TickPrice(object sender, TickPriceEventArgs e)
        {
            if (LastFeeds.ContainsKey(e.TickerId))
            {
                var emitMarketData = false;
                var emitTrade = false;
                var emitlevelOne = false;

                switch (e.TickType)
                {
                    case TickType.AskPrice:
                        emitlevelOne = true;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Ask = e.Price;
                        LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Ask_1;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Time = Time.Now;
                        break;
                    case TickType.BidPrice:
                        emitlevelOne = true;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Bid = e.Price;
                        LastFeeds[e.TickerId].Blotter.TickInfo = TickInfo.Bid_1;
                        LastFeeds[e.TickerId].Blotter[QuoteLevel.One].Time = Time.Now;
                        break;
                    case TickType.ClosePrice:
                        LastFeeds[e.TickerId].Marketdata.Close = e.Price;
                        emitMarketData = true;
                        break;
                    case TickType.OpenPrice:
                        LastFeeds[e.TickerId].Marketdata.Open = e.Price;
                        emitMarketData = true;
                        break;
                    case TickType.HighPrice:
                        LastFeeds[e.TickerId].Marketdata.High = e.Price;
                        emitMarketData = true;
                        break;
                    case TickType.LowPrice:
                        LastFeeds[e.TickerId].Marketdata.Low = e.Price;
                        emitMarketData = true;
                        break;
                    case TickType.LastPrice:
                        emitTrade = true;
                        LastFeeds[e.TickerId].Trade.Price = e.Price;
                        LastFeeds[e.TickerId].Trade.Time = Time.Now;
                        break;
                }

                if (emitTrade && LastFeeds[e.TickerId].TradeCheck)
                {
                    LastFeeds[e.TickerId].Trade.TickInfo = TickInfo.LastTrade;
                    _EmitNewTrade(this, LastFeeds[e.TickerId].Trade);
                }
                else
                    LastFeeds[e.TickerId].CheckTrade();

                if (emitlevelOne)
                    _EmitNewBlotter(this, LastFeeds[e.TickerId].Blotter);

                if (emitMarketData)
                    _EmitNewMarketData(this, LastFeeds[e.TickerId].Marketdata);
            }
        }
        private void ContractDetails(object sender, ContractDetailsEventArgs e)
        {
            CultureInfo provider = CultureInfo.InvariantCulture;
            var ticker = new DBTickers();
            using (var db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString()))
            {
                var query = db.DBTickers.Where(u => u.Provider == PROVIDER_NAME && u.Ticker == e.ContractDetails.Summary.Symbol);

                if (!query.Any())
                    ticker = db.DBTickers.Where(u => u.Provider == PROVIDER_NAME && u.Ticker == e.ContractDetails.MarketName).FirstOrDefault();
                else
                    ticker = query.FirstOrDefault();

                ticker.DBInstrumentsReference.Load();
                ticker.DBInstruments.DBRulesReference.Load();
                ticker.DBInstruments.ISIN = e.ContractDetails.Cusip ?? String.Empty;

                DateTime settlementDate;
                if (DateTime.TryParseExact(e.ContractDetails.Summary.Expiry, "yyyyMMdd", provider, DateTimeStyles.AssumeLocal, out settlementDate))
                {
                    if (ticker.DBInstruments.Maturity == null)
                        ticker.DBInstruments.Maturity = settlementDate;
                    else if(settlementDate > ticker.DBInstruments.Maturity && DateTime.Now > ticker.DBInstruments.Maturity )
                        ticker.DBInstruments.Maturity = settlementDate;
                }

                var tickValue = 1.0;
                if (double.TryParse(e.ContractDetails.Summary.Multiplier, NumberStyles.Float, provider, out tickValue))
                    ticker.DBInstruments.DBRules.TickValue = tickValue;

                ticker.DBInstruments.DBRules.Tick = e.ContractDetails.MinTick;
                _EmitError(this, new FireMessageEventArgs(ticker.DBInstruments.Name + " Details Updated", DateTime.Now.TimeOfDay));
                db.SaveChanges(true);
            }
        }
        private void ConnectionClosed(object sender, ConnectionClosedEventArgs e)
        {
            if (client.Stopped)
            {
                _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
                _EmitError(this, new FireMessageEventArgs("IB Connection ShutDown", Time.Now.TimeOfDay));
            }
        }
        private void HistoricalData(object sender, HistoricalDataEventArgs e)
        {
            var size = (int)HistoricalRequests[e.RequestId].BarSize;
            var id = HistoricalRequests[e.RequestId].Id;

            HistoricalRequests[e.RequestId].Add(new Bar(e.Date - new TimeSpan(0, 0, 0, size), e.Date, e.Open, e.High, e.Low, e.Close, size, e.Volume, 0) { Id = id, isComplete = (e.HasGaps ? false : true) });

            if (e.RecordNumber == e.RecordTotal - 1)
            {
                _EmitBarSeries(this, HistoricalRequests[e.RequestId]);
                _EmitError(this, new FireMessageEventArgs(e.RecordNumber + " Bars filled for" + HistoricalRequests[e.RequestId].Ticker, Time.Now.TimeOfDay));
            }
        }
        private static void NextValidId(object sender, NextValidIdEventArgs e)
        {
            NextOrderId = e.OrderId;
        }

        #endregion IB's Feed CallBacks
    }
}